package org.dxy.domain.model.aggregate.impl;

import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.command.equipment.ReassignTaskDueToFailureCommand;
import org.dxy.domain.command.workorder.*;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.event.workorder.*;
import org.dxy.domain.model.aggregate.Equipment;
import org.dxy.domain.model.aggregate.WorkOrder;
import org.dxy.domain.model.valobj.WorkOrderId;
import org.dxy.domain.model.valobj.WorkOrderStatusEnum;

import java.util.Collections;
import java.util.List;
import java.util.ArrayList;

/**
 * @description: 工单聚合根实现类
 * @author: dxy 
 * @createTime: 2025/6/22 17:26 
 */
@Slf4j
@Getter
@Builder
public class WorkOrderAggRoot implements WorkOrder {
    /** 工单ID */
    private WorkOrderId workOrderId;
    /** 工单编码 */
    private String workOrderCode;
    /** 产品型号 */
    private String productModel;
    /** 工艺路线编码 */
    private String routeCode;
    /** 产线编码 */
    private String productionLineCode;
    /** 计划数量 */
    private Integer plannedQuantity;
    /** 工单状态 */
    private WorkOrderStatusEnum status;

    // === 事件集合 ===
    private final List<DomainEvent> domainEvents = new ArrayList<>();

    // === 事件相关方法 ===
    @Override
    public List<DomainEvent> getDomainEvents() {
        return Collections.unmodifiableList(domainEvents);
    }

    @Override
    public void addDomainEvent(DomainEvent event) {
        domainEvents.add(event);
    }

    @Override
    public void clearDomainEvents() {
        domainEvents.clear();
    }

    @Override
    public boolean hasDomainEvents() {
        return !domainEvents.isEmpty();
    }

    @Override
    public boolean hasNoDomainEvents() {
        return domainEvents.isEmpty();
    }

    // === 业务方法 ===
    public static WorkOrder create(Long workOrderId, CreateWorkOrderCommand command) {

        // 校验计划数量必须大于0
        if (command.getPlannedQuantity() != null && command.getPlannedQuantity() <= 0) {
            throw new IllegalArgumentException("计划数量必须大于0");
        }

        WorkOrderAggRoot workOrder = WorkOrderAggRoot.builder()
                .workOrderId(WorkOrderId.of(workOrderId))
                .workOrderCode(command.getWorkOrderCode())
                .productModel(command.getProductModel())
                .plannedQuantity(command.getPlannedQuantity())
                .routeCode(command.getRouteCode())
                .productionLineCode(command.getProductionLineCode())
                .status(WorkOrderStatusEnum.CREATED)
                .build();

        workOrder.addDomainEvent(new WorkOrderCreatedEvent(
                workOrder.getWorkOrderId().getValue(),
                workOrder.getWorkOrderCode(),
                workOrder.getProductModel(),
                workOrder.getStatus().getKey()
        ));

        return workOrder;
    }

    @Override
    public void release(ReleaseWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.CREATED) {
            throw new IllegalStateException("只有已创建状态的工单才能下达");
        }
        
        this.status = WorkOrderStatusEnum.RELEASED;
        addDomainEvent(new WorkOrderReleasedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                this.status.getKey()
        ));
    }

    @Override
    public void start(StartWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.RELEASED) {
            throw new IllegalStateException("只有已下达状态的工单才能开始生产");
        }
        
        this.status = WorkOrderStatusEnum.STARTED;
        addDomainEvent(new WorkOrderStartedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                this.status.getKey()
        ));
    }

    @Override
    public void suspend(org.dxy.domain.command.workorder.SuspendWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.STARTED) {
            throw new IllegalStateException("只有生产中的工单才能暂停");
        }
        
        this.status = WorkOrderStatusEnum.SUSPENDED;
        addDomainEvent(new WorkOrderSuspendedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                this.status.getKey()
        ));
    }

    @Override
    public void resume(ResumeWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.SUSPENDED) {
            throw new IllegalStateException("只有暂停状态的工单才能恢复");
        }
        
        this.status = WorkOrderStatusEnum.STARTED;
        addDomainEvent(new WorkOrderResumedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                this.status.getKey()
        ));
    }

    @Override
    public void complete(CompleteWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.STARTED) {
            throw new IllegalStateException("只有生产中的工单才能完成");
        }
        
        this.status = WorkOrderStatusEnum.COMPLETED;
        addDomainEvent(new WorkOrderCompletedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                command.getCompletedQuantity(),
                this.status.getKey()
        ));
    }

    @Override
    public void close(CloseWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.COMPLETED) {
            throw new IllegalStateException("只有已完成的工单才能关闭");
        }
        
        this.status = WorkOrderStatusEnum.CLOSED;
        addDomainEvent(new WorkOrderClosedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                "工单正常关闭", // 默认关闭原因，实际应该从请求中获取
                this.status.getKey()
        ));
    }

    @Override
    public void cancel(CancelWorkOrderCommand command) {
        if (status == WorkOrderStatusEnum.COMPLETED || status == WorkOrderStatusEnum.CLOSED) {
            throw new IllegalStateException("已完成或已关闭的工单不能取消");
        }
        
        this.status = WorkOrderStatusEnum.CANCELLED;
        addDomainEvent(new WorkOrderCancelledEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                "工单取消", // 默认取消原因，实际应该从请求中获取
                this.status.getKey()
        ));
    }

    @Override
    public void reassignTaskDueToFailure(ReassignTaskDueToFailureCommand command, Equipment original, Equipment target) {
        // 设备故障任务重分配逻辑
    }

    @Override
    public void update(String workOrderCode, String productModel, Integer plannedQuantity, String routeCode, String productionLineCode) {
        // 校验计划数量必须大于0
        if (plannedQuantity != null && plannedQuantity <= 0) {
            throw new IllegalArgumentException("计划数量必须大于0");
        }

        // 更新工单信息
        this.workOrderCode = workOrderCode;
        this.productModel = productModel;
        this.plannedQuantity = plannedQuantity;
        this.routeCode = routeCode;
        this.productionLineCode = productionLineCode;

        // 发布工单更新事件
        addDomainEvent(new WorkOrderUpdatedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                plannedQuantity,
                routeCode,
                productionLineCode,
                this.status.getKey()
        ));
    }

    @Override
    public void delete() {
        // 发布工单删除事件
        addDomainEvent(new WorkOrderDeletedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productModel,
                this.status.getKey()
        ));
    }

    @Override
    public boolean canUpdate() {
        // 只有已创建和已下达状态的工单可以更新
        return status == WorkOrderStatusEnum.CREATED || status == WorkOrderStatusEnum.RELEASED;
    }

    @Override
    public boolean canDelete() {
        // 只有已创建、已取消、已关闭状态的工单可以删除
        return status == WorkOrderStatusEnum.CREATED ||
               status == WorkOrderStatusEnum.CANCELLED ||
               status == WorkOrderStatusEnum.CLOSED;
    }

    // === 事件应用方法 ===
    /**
     * 应用工单创建事件
     */
    public void applyCreatedEvent(WorkOrderCreatedEvent event) {
        this.workOrderCode = event.workOrderCode();
        this.productModel = event.productModel();
        this.status = WorkOrderStatusEnum.CREATED;
    }

    /**
     * 应用工单更新事件
     */
    public void applyUpdatedEvent(WorkOrderUpdatedEvent event) {
        this.workOrderCode = event.workOrderCode();
        this.productModel = event.productModel();
        this.plannedQuantity = event.plannedQuantity();
        this.routeCode = event.routeCode();
        this.productionLineCode = event.productionLineCode();
    }

    /**
     * 应用工单下达事件
     */
    public void applyReleasedEvent(WorkOrderReleasedEvent event) {
        this.status = WorkOrderStatusEnum.RELEASED;
    }

    /**
     * 应用工单开始事件
     */
    public void applyStartedEvent(WorkOrderStartedEvent event) {
        this.status = WorkOrderStatusEnum.STARTED;
    }

    /**
     * 应用工单暂停事件
     */
    public void applySuspendedEvent(WorkOrderSuspendedEvent event) {
        this.status = WorkOrderStatusEnum.SUSPENDED;
    }

    /**
     * 应用工单恢复事件
     */
    public void applyResumedEvent(WorkOrderResumedEvent event) {
        this.status = WorkOrderStatusEnum.STARTED;
    }

    /**
     * 应用工单完成事件
     */
    public void applyCompletedEvent(WorkOrderCompletedEvent event) {
        this.status = WorkOrderStatusEnum.COMPLETED;
    }

    /**
     * 应用工单关闭事件
     */
    public void applyClosedEvent(WorkOrderClosedEvent event) {
        this.status = WorkOrderStatusEnum.CLOSED;
    }

    /**
     * 应用工单取消事件
     */
    public void applyCancelledEvent(WorkOrderCancelledEvent event) {
        this.status = WorkOrderStatusEnum.CANCELLED;
    }

    /**
     * 应用工单删除事件
     */
    public void applyDeletedEvent(WorkOrderDeletedEvent event) {
        // 删除事件通常不会改变聚合状态，因为聚合已被删除
        log.warn("工单ID {} 的工单已被删除，尝试回放删除事件。", event.workOrderId());
    }
}
